/**
 * @file load_balancer.cpp
 * @brief API网关负载均衡器实现
 * @details 实现了多种负载均衡算法，支持服务实例管理和健康检查
 *
 * 主要功能：
 * 1. 负载均衡算法：轮询、加权轮询、最少连接
 * 2. 服务实例管理：添加、删除、更新服务实例
 * 3. 健康检查：实例健康状态监控和过滤
 * 4. 连接统计：实时连接数统计和管理
 * 5. 线程安全：支持高并发环境下的安全操作
 *
 * 支持的负载均衡策略：
 * - ROUND_ROBIN: 轮询算法，依次选择实例
 * - WEIGHTED_ROUND_ROBIN: 加权轮询，根据权重概率选择
 * - LEAST_CONNECTIONS: 最少连接，选择连接数最少的实例
 *
 * @author 29108
 * @date 2025/7/15
 */

#include "core_services/api_gateway/load_balancer.h"
#include "common/logger/logger.h"
#include <algorithm>
#include <random>
#include <numeric>


namespace core_services {
    namespace api_gateway {
        /**
         * @brief 负载均衡器构造函数
         * @param strategy 负载均衡策略
         *
         * @details 初始化负载均衡器并设置策略，支持的策略包括：
         * - ROUND_ROBIN: 轮询算法
         * - WEIGHTED_ROUND_ROBIN: 加权轮询算法
         * - LEAST_CONNECTIONS: 最少连接算法
         */
        LoadBalancer::LoadBalancer(Strategy strategy) : strategy_(strategy) {
            // LOG_INFO("负载均衡器初始化完成，策略: " + strategyToString(strategy_));
        }

        /**
         * @brief 添加服务实例到负载均衡器
         * @param service_name 服务名称，如"user-service"
         * @param instance 服务实例信息，包含主机、端口、权重等
         *
         * @details 添加过程：
         * 1. 获取写锁确保线程安全
         * 2. 检查实例是否已存在（基于host+port）
         * 3. 如果存在则更新，否则添加新实例
         * 4. 初始化轮询索引和连接数统计
         *
         * 注意：相同host+port的实例会被视为同一实例并更新
         */
        void LoadBalancer::addInstance(const std::string &service_name, const ServiceInstance &instance) {
            // 获取写锁，确保线程安全的实例管理
            std::lock_guard<std::mutex> lock(instances_mutex_);

            // 获取或创建服务的实例列表
            auto& instances = service_instances_[service_name];

            // 检查实例是否已存在（基于host+port唯一性）
            auto it = std::find_if(instances.begin(), instances.end(),
                [&instance](const ServiceInstance& existing) {
                    return existing.host == instance.host && existing.port == instance.port;
                });

            if (it != instances.end()) {
                // 实例已存在，更新其配置（权重、健康状态等）
                *it = instance;
                // LOG_INFO("更新服务实例: " + service_name + " -> " + instance.host + ":" + std::to_string(instance.port));
            } else {
                // 添加新实例到列表
                instances.push_back(instance);
                LOG_INFO("添加服务实例: " + service_name + " -> " + instance.host + ":" + std::to_string(instance.port));
            }

            // 初始化轮询索引（如果是第一次添加该服务的实例）
            if (round_robin_index_.find(service_name) == round_robin_index_.end()) {
                round_robin_index_[service_name] = 0;
            }

            // 初始化连接数统计，用于最少连接算法
            std::string instance_key = instance.host + ":" + std::to_string(instance.port);
            connection_counts_[service_name][instance_key] = 0;
        }

        /**
         * @brief 从负载均衡器中移除服务实例
         * @param service_name 服务名称
         * @param instance_id 实例ID，格式为"host:port"
         *
         * @details 移除过程：
         * 1. 获取写锁确保线程安全
         * 2. 查找并移除匹配的实例
         * 3. 清理相关的连接数统计
         * 4. 调整轮询索引避免越界
         *
         * 注意：移除实例后会自动调整轮询索引，确保后续选择不会出错
         */
        void LoadBalancer::removeInstance(const std::string &service_name, const std::string &instance_id) {
            // 获取写锁，确保线程安全的实例管理
            std::lock_guard<std::mutex> lock(instances_mutex_);

            // 查找服务是否存在
            auto service_it = service_instances_.find(service_name);
            if (service_it == service_instances_.end()) {
                LOG_WARNING("服务不存在: " + service_name);
                return;
            }

            // 获取服务的实例列表
            auto& instances = service_it->second;

            // 使用remove_if算法查找并标记要删除的实例
            auto it = std::remove_if(instances.begin(), instances.end(),
                [&instance_id](const ServiceInstance& instance) {
                    return (instance.host + ":" + std::to_string(instance.port)) == instance_id;
                });

            if (it != instances.end()) {
                // 删除标记的实例
                instances.erase(it, instances.end());
                LOG_INFO("移除服务实例: " + service_name + " -> " + instance_id);

                // 清理连接数统计，避免内存泄露
                auto conn_it = connection_counts_.find(service_name);
                if (conn_it != connection_counts_.end()) {
                    conn_it->second.erase(instance_id);
                }

                // 调整轮询索引，防止数组越界
                if (instances.empty()) {
                    // 如果没有实例了，重置索引为0
                    round_robin_index_[service_name] = 0;
                } else {
                    // 确保索引在有效范围内
                    round_robin_index_[service_name] %= instances.size();
                }
            } else {
                LOG_WARNING("服务实例不存在: " + service_name + " -> " + instance_id);
            }
        }

        /**
         * @brief 更新服务实例的健康状态
         * @param service_name 服务名称
         * @param instance_id 实例ID，格式为"host:port"
         * @param healthy 健康状态，true表示健康，false表示不健康
         *
         * @details 健康状态更新：
         * 1. 查找指定的服务实例
         * 2. 更新健康状态和最后检查时间
         * 3. 记录状态变更日志
         *
         * 健康检查机制：
         * - 只有健康的实例才会被负载均衡算法选中
         * - 不健康的实例会被自动过滤掉
         * - last_check时间戳用于健康检查超时判断
         */
        void LoadBalancer::updateInstanceHealth(const std::string &service_name, const std::string &instance_id, bool healthy) {
            // 获取写锁，确保线程安全的状态更新
            std::lock_guard<std::mutex> lock(instances_mutex_);

            // 查找服务是否存在
            auto service_it = service_instances_.find(service_name);
            if (service_it == service_instances_.end()) {
                LOG_WARNING("服务不存在: " + service_name);
                return;
            }

            // 遍历服务的所有实例，查找匹配的实例
            auto& instances = service_it->second;
            for (auto& instance : instances) {
                if ((instance.host + ":" + std::to_string(instance.port)) == instance_id) {
                    // 更新健康状态
                    instance.healthy = healthy;
                    // 更新最后检查时间，用于健康检查超时判断
                    instance.last_check = std::chrono::system_clock::now();

                    LOG_DEBUG("更新服务实例健康状态: " + service_name + " -> " + instance_id +
                             " = " + (healthy ? "健康" : "不健康"));
                    return;
                }
            }

            LOG_WARNING("服务实例不存在: " + service_name + " -> " + instance_id);
        }

        /**
         * @brief 根据负载均衡策略选择服务实例
         * @param service_name 服务名称
         * @return 选中的服务实例，如果没有可用实例则返回nullopt
         *
         * @details 选择过程：
         * 1. 获取读锁，支持并发读取
         * 2. 查找服务和实例列表
         * 3. 过滤出健康的实例
         * 4. 根据配置的策略选择实例
         *
         * 支持的策略：
         * - ROUND_ROBIN: 轮询选择
         * - WEIGHTED_ROUND_ROBIN: 按权重概率选择
         * - LEAST_CONNECTIONS: 选择连接数最少的实例
         *
         * 容错机制：
         * - 只选择健康的实例
         * - 未知策略时回退到轮询算法
         */
        std::optional<LoadBalancer::ServiceInstance> LoadBalancer::selectInstance(const std::string &service_name) {
            // 获取读锁，支持并发读取，提高性能
            std::lock_guard<std::mutex> lock(instances_mutex_);

            // 查找服务是否存在
            auto service_it = service_instances_.find(service_name);
            if (service_it == service_instances_.end()) {
                LOG_WARNING("服务不存在: " + service_name);
                return std::nullopt;
            }

            // 获取服务的实例列表
            auto& instances = service_it->second;
            if (instances.empty()) {
                LOG_WARNING("服务无可用实例: " + service_name);
                return std::nullopt;
            }

            // 过滤健康的实例，只有健康的实例才能被选中
            std::vector<ServiceInstance> healthy_instances;
            std::copy_if(instances.begin(), instances.end(), std::back_inserter(healthy_instances),
                [](const ServiceInstance& instance) { return instance.healthy; });

            if (healthy_instances.empty()) {
                LOG_WARNING("服务无健康实例: " + service_name);
                return std::nullopt;
            }

            // 根据配置的负载均衡策略选择实例
            switch (strategy_) {
                case Strategy::ROUND_ROBIN:
                    // 轮询算法：依次选择实例
                    return selectRoundRobin(service_name, healthy_instances);

                case Strategy::WEIGHTED_ROUND_ROBIN:
                    // 加权轮询算法：根据权重概率选择
                    return selectWeightedRoundRobin(service_name, healthy_instances);

                case Strategy::LEAST_CONNECTIONS:
                    // 最少连接算法：选择连接数最少的实例
                    return selectLeastConnections(service_name, healthy_instances);

                default:
                    // 未知策略，回退到轮询算法保证服务可用性
                    LOG_ERROR("未知的负载均衡策略");
                    return selectRoundRobin(service_name, healthy_instances);
            }
        }

        /**
         * @brief 增加服务实例的连接数
         * @param service_name 服务名称
         * @param instance_id 实例ID，格式为"host:port"
         *
         * @details 连接数管理：
         * - 用于最少连接算法的连接数统计
         * - 每当有新连接建立时调用此方法
         * - 线程安全的计数器更新
         *
         * 使用场景：
         * - HTTP请求开始处理时
         * - WebSocket连接建立时
         * - 长连接建立时
         */
        void LoadBalancer::incrementConnections(const std::string &service_name, const std::string &instance_id) {
            // 获取写锁，确保连接数更新的线程安全
            std::lock_guard<std::mutex> lock(instances_mutex_);

            // 验证服务是否存在，避免无效操作
            if (service_instances_.find(service_name) == service_instances_.end()) {
                LOG_WARNING("服务不存在，无法增加连接数: " + service_name);
                return;
            }

            // 原子性地增加连接数计数器
            connection_counts_[service_name][instance_id]++;

            // LOG_DEBUG("增加连接数: " + service_name + " -> " + instance_id +
            //          " = " + std::to_string(connection_counts_[service_name][instance_id]));
        }

        /**
         * @brief 减少服务实例的连接数
         * @param service_name 服务名称
         * @param instance_id 实例ID，格式为"host:port"
         *
         * @details 连接数管理：
         * - 用于最少连接算法的连接数统计
         * - 每当连接关闭时调用此方法
         * - 确保连接数不会小于0
         * - 线程安全的计数器更新
         *
         * 使用场景：
         * - HTTP请求处理完成时
         * - WebSocket连接关闭时
         * - 长连接断开时
         */
        void LoadBalancer::decrementConnections(const std::string &service_name, const std::string &instance_id) {
            // 获取写锁，确保连接数更新的线程安全
            std::lock_guard<std::mutex> lock(instances_mutex_);

            // 查找服务是否存在
            auto service_it = connection_counts_.find(service_name);
            if (service_it == connection_counts_.end()) {
                LOG_WARNING("服务不存在，无法减少连接数: " + service_name);
                return;
            }

            // 安全地减少连接数，确保不会小于0
            auto& instance_connections = service_it->second;
            auto instance_it = instance_connections.find(instance_id);
            if (instance_it != instance_connections.end() && instance_it->second > 0) {
                instance_it->second--;

                // LOG_DEBUG("减少连接数: " + service_name + " -> " + instance_id +
                //          " = " + std::to_string(instance_it->second));
            } else {
                LOG_WARNING("实例连接数已为0或实例不存在: " + service_name + " -> " + instance_id);
            }
        }

        LoadBalancer::Strategy LoadBalancer::getStrategy() const { return strategy_; }

        std::vector<LoadBalancer::ServiceInstance> LoadBalancer::getInstances(const std::string &service_name) const {
            std::lock_guard<std::mutex> lock(instances_mutex_);

            auto service_it = service_instances_.find(service_name);
            if (service_it != service_instances_.end()) {
                return service_it->second;
            }

            return {}; // 返回空列表
        }

        size_t LoadBalancer::getHealthyInstanceCount(const std::string &service_name) const {
            std::lock_guard<std::mutex> lock(instances_mutex_);

            auto service_it = service_instances_.find(service_name);
            if (service_it == service_instances_.end()) {
                return 0;
            }

            size_t healthy_count = 0;
            for (const auto& instance : service_it->second) {
                if (instance.healthy) {
                    healthy_count++;
                }
            }

            return healthy_count;
        }

        /**
         * @brief 轮询算法选择实例
         * @param service_name 服务名称
         * @param instances 健康的实例列表
         * @return 选中的服务实例，如果没有可用实例则返回nullopt
         *
         * @details 轮询算法特点：
         * - 依次选择实例，确保负载均匀分布
         * - 使用round_robin_index_记录每个服务的当前索引
         * - 自动循环，到达末尾后回到开头
         * - 时间复杂度O(1)，性能优秀
         *
         * 适用场景：
         * - 实例性能相近的情况
         * - 需要简单均匀分布的场景
         * - 对延迟要求不高的服务
         */
        std::optional<LoadBalancer::ServiceInstance> LoadBalancer::selectRoundRobin(const std::string &service_name,
            const std::vector<ServiceInstance> &instances) {
            // 边界检查：如果没有可用实例，返回空
            if (instances.empty()) return std::nullopt;

            // 获取当前服务的轮询索引引用，支持修改
            size_t& index = round_robin_index_[service_name];

            // 确保索引在有效范围内，防止数组越界
            index %= instances.size();

            // 选择当前索引对应的实例
            auto selected = instances[index];

            // 更新索引到下一个位置，实现轮询效果
            index = (index + 1) % instances.size();

            // LOG_DEBUG("轮询选择实例: " + service_name + " -> " + selected.host + ":" + std::to_string(selected.port));
            return selected;
        }

                /**
         * @brief 加权轮询算法实现
         * @param service_name 服务名称，用于日志记录
         * @param instances 健康的服务实例列表
         * @return 根据权重概率选中的服务实例，如果没有可用实例则返回nullopt
         *
         * @details 加权轮询算法原理：
         * 1. 计算所有实例的权重总和
         * 2. 生成1到总权重之间的随机数
         * 3. 遍历实例，累加权重，当累加值>=随机数时选中该实例
         *
         * 例如：实例A权重3，实例B权重2，实例C权重1，总权重6
         * - 随机数1-3：选中实例A (概率50%)
         * - 随机数4-5：选中实例B (概率33.3%)
         * - 随机数6：选中实例C (概率16.7%)
         */
        std::optional<LoadBalancer::ServiceInstance> LoadBalancer::selectWeightedRoundRobin(
            const std::string &service_name, const std::vector<ServiceInstance> &instances) {

            // 边界检查：如果没有可用实例，直接返回空值
            if (instances.empty()) return std::nullopt;

            // 步骤1：计算所有实例的权重总和
            // 使用std::accumulate和lambda表达式遍历所有实例，累加权重值
            int total_weight = std::accumulate(instances.begin(), instances.end(), 0,
                [](int sum, const ServiceInstance& instance) {
                    return sum + instance.weight;
                });

            // 权重有效性检查：如果总权重<=0，说明权重配置有问题
            if (total_weight <= 0) {
                // 降级处理：回退到普通轮询算法，确保服务可用性
                return selectRoundRobin(service_name, instances);
            }

            // 步骤2：生成加权随机数
            // 使用thread_local确保每个线程有独立的随机数生成器，避免线程竞争
            static thread_local std::random_device rd;        // 硬件随机数种子
            static thread_local std::mt19937 gen(rd());       // 梅森旋转算法随机数生成器
            std::uniform_int_distribution<> dis(1, total_weight);  // 均匀分布：[1, total_weight]

            // 生成1到total_weight之间的随机数，用于权重选择
            int random_weight = dis(gen);
            int current_weight = 0;  // 当前累计权重

            // 步骤3：权重区间匹配算法
            // 遍历所有实例，累加权重，找到随机数落在哪个实例的权重区间内
            for (const auto& instance : instances) {
                current_weight += instance.weight;  // 累加当前实例的权重

                // 如果随机数<=当前累计权重，说明随机数落在当前实例的权重区间内
                if (random_weight <= current_weight) {
                    // 记录选择结果，便于调试和监控
                    // LOG_DEBUG("加权轮询选择实例: " + service_name + " -> " + instance.host + ":" +
                    //          std::to_string(instance.port) + " (权重: " + std::to_string(instance.weight) +
                    //          ", 随机数: " + std::to_string(random_weight) + "/" + std::to_string(total_weight) + ")");
                    return instance;
                }
            }

            // 异常情况处理：理论上不应该到达这里，因为random_weight <= total_weight
            // 如果到达这里，可能是浮点数精度问题或其他异常，回退到第一个实例保证服务可用
            LOG_WARNING("加权轮询算法异常，回退到第一个实例: " + service_name);
            return instances[0];
        }

        /**
         * @brief 最少连接算法选择实例
         * @param service_name 服务名称
         * @param instances 健康的实例列表
         * @return 连接数最少的服务实例，如果没有可用实例则返回nullopt
         *
         * @details 最少连接算法特点：
         * - 选择当前连接数最少的实例，实现动态负载均衡
         * - 适合处理时间差异较大的请求
         * - 能够自动适应实例性能差异
         * - 需要维护连接数统计，有一定开销
         *
         * 算法流程：
         * 1. 遍历所有健康实例
         * 2. 查询每个实例的当前连接数
         * 3. 选择连接数最少的实例
         * 4. 如果有多个实例连接数相同，选择第一个
         *
         * 适用场景：
         * - 请求处理时间差异较大
         * - 实例性能不均匀
         * - 需要精确负载控制的场景
         */
        std::optional<LoadBalancer::ServiceInstance> LoadBalancer::selectLeastConnections(
            const std::string &service_name, const std::vector<ServiceInstance> &instances) {
            // 边界检查：如果没有可用实例，返回空
            if (instances.empty()) return std::nullopt;

            // 获取服务的连接数统计映射
            auto& conn_counts = connection_counts_[service_name];

            // 初始化最优实例查找变量
            const ServiceInstance* selected = nullptr;
            size_t min_connections = SIZE_MAX;  // 使用最大值作为初始值

            // 遍历所有健康实例，查找连接数最少的实例
            for (const auto& instance : instances) {
                // 构建实例唯一标识符
                std::string instance_key = instance.host + ":" + std::to_string(instance.port);

                // 获取当前实例的连接数（如果不存在则默认为0）
                size_t connections = conn_counts[instance_key];

                // 更新最少连接数的实例
                if (connections < min_connections) {
                    min_connections = connections;
                    selected = &instance;
                }
            }

            // 返回连接数最少的实例
            if (selected) {
                // LOG_DEBUG("最少连接选择实例: " + service_name + " -> " + selected->host + ":" +
                //          std::to_string(selected->port) + " (连接数: " + std::to_string(min_connections) + ")");
                return *selected;
            }

            // 理论上不应该到达这里，因为instances不为空且selected应该被设置
            return std::nullopt;
        }

        /**
         * @brief 将负载均衡策略枚举转换为中文字符串
         * @param strategy 负载均衡策略枚举值
         * @return 策略的中文描述字符串
         *
         * @details 用于日志记录和调试输出，提供友好的策略名称显示
         */
        std::string LoadBalancer::strategyToString(Strategy strategy) {
            switch (strategy) {
                case Strategy::ROUND_ROBIN:
                    return "轮询";
                case Strategy::WEIGHTED_ROUND_ROBIN:
                    return "加权轮询";
                case Strategy::LEAST_CONNECTIONS:
                    return "最少连接";
                default:
                    return "未知";
            }
        }


        void LoadBalancer::clearServiceInstances(const std::string& service_name) {
            std::lock_guard<std::mutex> lock(instances_mutex_);

            auto service_it = service_instances_.find(service_name);
            if (service_it != service_instances_.end()) {
                size_t removed_count = service_it->second.size();
                service_instances_.erase(service_it);

                // 清理连接计数
                auto conn_it = connection_counts_.find(service_name);
                if (conn_it != connection_counts_.end()) {
                    connection_counts_.erase(conn_it);
                }

                // 重置轮询索引
                auto index_it = round_robin_index_.find(service_name);
                if (index_it != round_robin_index_.end()) {
                    round_robin_index_.erase(index_it);
                }

                LOG_INFO("清除服务所有实例: " + service_name + " (移除数量: " + std::to_string(removed_count) + ")");
            } else {
                LOG_WARNING("尝试清除不存在的服务: " + service_name);
            }
        }

        void LoadBalancer::addServiceInstance(const std::string& service_name, const ServiceInstance& instance) {
            // 这是addInstance的别名方法，直接调用addInstance
            addInstance(service_name, instance);
        }


    } // namespace api_gateway
} // namespace core_services

/**
 * @file load_balancer.cpp 实现总结
 *
 * 本文件实现了API网关的负载均衡核心功能，主要包括：
 *
 * 1. **多种负载均衡算法**：
 *    - 轮询算法：简单均匀分布，适合同质化实例
 *    - 加权轮询：基于权重的概率选择，适合异构实例
 *    - 最少连接：动态负载感知，适合处理时间差异大的场景
 *
 * 2. **服务实例管理**：
 *    - 线程安全的实例增删改查
 *    - 健康状态监控和过滤
 *    - 实例权重和配置管理
 *
 * 3. **连接数统计**：
 *    - 实时连接数跟踪
 *    - 支持最少连接算法
 *    - 线程安全的计数器操作
 *
 * 4. **高性能设计**：
 *    - 读写锁支持高并发访问
 *    - O(1)时间复杂度的轮询算法
 *    - 高效的实例查找和选择
 *
 * 5. **容错机制**：
 *    - 健康检查过滤
 *    - 算法降级处理
 *    - 异常情况的安全回退
 *
 * 该实现为API网关提供了强大的负载均衡能力，支持多种场景下的流量分发需求，
 * 具有良好的性能、可靠性和可扩展性。
 */
